unit JATUIF_Driver_SoundEx;

{$mode objfpc}{$H+}

interface

uses
    Classes, SysUtils, Contnrs, MMSystem, BASS;

type

    TChannel = Record
        Name   : String;
        Chan   : DWORD;
    end;
    PChannel = ^TChannel;

    { TSoundDriverEx }

    TSoundDriverEx = class
      Public
        Constructor Create;
        Function GetVolume : Float;
        Procedure SetVolume(Volume : Float);
        Procedure NewChannel(Name : String; URI : String; Loop : Boolean);
        Procedure PlayChannel(Name : String);
        Procedure StopChannel(Name : String);
        Procedure RestartChannel(Name : String);
        Procedure PauseChannel(Name : String);
        Function GetChannelLengthSeconds(Name : String) : Double;
        Function GetChannelPositionSeconds(Name : String) : Double;
        Procedure SetChannelPositionSeconds(Name : String; Position : Double);
        Function GetChannelLength(Name : String) : QWORD;
        Function GetChannelPosition(Name : String) : QWORD;
        Procedure SetChannelPosition(Name : String; Position : QWORD);
      Private
        Channels : TList;
        Function NameToChan(Name : String) : DWORD;
        Function ChanToName(Chan : DWORD)  : String;
        Function CreateChannel(URI : String; Loop : Boolean) : DWORD;
        Procedure Stop(Chan : DWORD);
        Procedure Play(Chan : DWORD);
        Procedure Restart(Chan : DWORD);
        Procedure Pause(Chan : DWORD);
    end;

implementation

constructor TSoundDriverEx.Create;
begin
     if not BASS_Init(-1,44100,0,0,nil) then begin
           //Failed to Init Channel.
     end else begin
         Channels:= TList.Create;
     end;
     inherited Create;
end;

function TSoundDriverEx.GetVolume: Float;
begin
     Try
        Result:= BASS_GetVolume;
     Except

     end;
end;

procedure TSoundDriverEx.SetVolume(Volume: Float);
begin
     Try
        BASS_SetVolume(Volume);
     Except

     end;
end;

procedure TSoundDriverEx.NewChannel(Name: String; URI: String; Loop: Boolean);
Var
   c : PChannel;

begin
     Try
        c:= new(PChannel);
        c^.Name:= Name;
        c^.Chan:= CreateChannel(URI, Loop);
        Channels.Add(c);
     Except

     end;
end;

procedure TSoundDriverEx.PlayChannel(Name: String);
Var
   Chan   : DWORD;

begin
     Try
        Chan:= NameToChan(Name);
        If Chan <> 0 then begin
           Play(Chan);
        end;
     Except

     end;
end;

procedure TSoundDriverEx.StopChannel(Name: String);
Var
   Chan   : DWORD;

begin
     Try
        Chan:= NameToChan(Name);
        If Chan <> 0 then begin
           Stop(Chan);
        end;
     Except

     end;
end;

procedure TSoundDriverEx.RestartChannel(Name: String);
Var
   Chan   : DWORD;

begin
     Try
        Chan:= NameToChan(Name);
        If Chan <> 0 then begin
           Restart(Chan);
        end;
     Except

     end;
end;

procedure TSoundDriverEx.PauseChannel(Name: String);
Var
   Chan   : DWORD;

begin
     Try
        Chan:= NameToChan(Name);
        If Chan <> 0 then begin
           Pause(Chan);
        end;
     Except

     end;
end;

function TSoundDriverEx.GetChannelLengthSeconds(Name: String) : Double;
Var
   Chan   : DWORD;
   Length : QWORD;

begin
     Try
        Chan:= NameToChan(Name);
        If Chan <> 0 then begin
           Length:= GetChannelLength(Name);
           Result:= BASS_ChannelBytes2Seconds(Chan, Length);
        end;
     Except

     end;
end;

function TSoundDriverEx.GetChannelPositionSeconds(Name: String): Double;
Var
   Chan : DWORD;
   Pos  : QWORD;

begin
     Try
        Chan:= NameToChan(Name);
        If Chan <> 0 then begin
           Pos:= GetChannelPosition(Name);
           Result:= BASS_ChannelBytes2Seconds(Chan, Pos);
        end;
     Except

     end;
end;

procedure TSoundDriverEx.SetChannelPositionSeconds(Name: String; Position: Double);
Var
   Chan : DWORD;
   Pos  : QWORD;

begin
     Try
        Chan:= NameToChan(Name);
        If Chan <> 0 then begin
           Pos:= BASS_ChannelSeconds2Bytes(Chan, Position);
           SetChannelPosition(Name, Pos);
        end;
     Except

     end;
end;

function TSoundDriverEx.GetChannelLength(Name: String): QWORD;
Var
   Chan : DWORD;

begin
     Try
        Chan:= NameToChan(Name);
        If Chan <> 0 then begin
           Result:= BASS_ChannelGetLength(Chan, BASS_POS_BYTE);
        end;
     Except

     end;
end;

function TSoundDriverEx.GetChannelPosition(Name: String): QWORD;
Var
   Chan : DWORD;

begin
     Try
        Chan:= NameToChan(Name);
        If Chan <> 0 then begin
           Result:= BASS_ChannelGetPosition(Chan, BASS_POS_BYTE);
        end;
     Except

     end;
end;

procedure TSoundDriverEx.SetChannelPosition(Name: String; Position: QWORD);
Var
   Chan : DWORD;

begin
     Try
        Chan:= NameToChan(Name);
        If Chan <> 0 then begin
           BASS_ChannelSetPosition(Chan, Position, BASS_POS_BYTE);
        end;
     Except

     end;
end;

function TSoundDriverEx.NameToChan(Name: String): DWORD;
Var
   i : integer;
   c : PChannel;

begin
     Result:= 0;
     For i:=0 to Channels.Count-1 do begin
         c:= Channels[i];
         If c^.Name = Name then begin
            Result:= c^.Chan;
            Break;
         end;
     end;
end;

function TSoundDriverEx.ChanToName(Chan: DWORD): String;
Var
   i : Integer;
   c : PChannel;

begin
     Result:= '';
     For i:=0 to Channels.Count-1 do begin
         c:= Channels[i];
         If c^.Chan = Chan then begin
            Result:= c^.Name;
            Break;
         end;
     end;
end;

function TSoundDriverEx.CreateChannel(URI: String; Loop: Boolean): DWORD;
Var
   Pos : QWORD;

begin
     Try
        If Loop then begin
           Result := BASS_StreamCreateFile(FALSE, PChar(URI), 0, 0, BASS_SAMPLE_LOOP);
           if (Result = 0) then Result := BASS_StreamCreateURL(PAnsiChar(AnsiString(URI)), 0, BASS_SAMPLE_LOOP, nil, nil);
           if (Result <> 0) then begin
              pos := BASS_ChannelGetLength(Result, BASS_POS_BYTE);
           end else begin
               Result := BASS_MusicLoad(FALSE, PChar(URI), 0, 0, BASS_MUSIC_LOOP or BASS_MUSIC_RAMPS or BASS_MUSIC_PRESCAN, 1);
           end;
        end else begin
            Result := BASS_StreamCreateFile(FALSE, PChar(URI), 0, 0, 0);
            if (Result = 0) then Result := BASS_StreamCreateURL(PAnsiChar(AnsiString(URI)), 0, 0, nil, nil);
            if (Result <> 0) then begin
               pos := BASS_ChannelGetLength(Result, BASS_POS_BYTE);
            end else begin
                Result := BASS_MusicLoad(FALSE, PChar(URI), 0, 0, BASS_MUSIC_RAMPS or BASS_MUSIC_PRESCAN, 1);
            end;
        end;
     Except
           Result:= 0;
     end;
end;

procedure TSoundDriverEx.Stop(Chan: DWORD);
begin
     Try
        BASS_ChannelStop(Chan);
        BASS_ChannelSetPosition(Chan, 0, BASS_POS_BYTE);
     Except
           //Exception Stuffs
     end;
end;

procedure TSoundDriverEx.Play(Chan: DWORD);
begin
     Try
        BASS_ChannelPlay(Chan, False);
     Except
           //Exception Stuffs
     end;
end;

procedure TSoundDriverEx.Restart(Chan: DWORD);
begin
     Try
        BASS_ChannelPlay(Chan, True);
     Except
           //Exception Stuffs
     end;
end;

procedure TSoundDriverEx.Pause(Chan: DWORD);
begin
     Try
        BASS_ChannelPause(Chan);
     Except
           //Exception Stuffs
     end;
end;


end.

